package cn.zhaozhiqi.article.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.zhaozhiqi.article.service.IArticleTypeService;
import cn.zhaozhiqi.article.vo.ArticleTypeTreeVO;
import cn.zhaozhiqi.exception.BussinessException;
import cn.zhaozhiqi.article.domain.ArticleType;
import cn.zhaozhiqi.article.mapper.ArticleTypeMapper;
import cn.zhaozhiqi.article.query.ArticleTypeQuery;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Transactional
@CacheConfig(cacheNames = "articleType")
public class ArticleTypeServiceImpl implements IArticleTypeService {

    @Autowired
    private ArticleTypeMapper articleTypeMapper;

    @Override
    public ArticleType getByID(Long id) {
        return articleTypeMapper.getByID(id);
    }

    @Override
    public List<ArticleType> getAll() {
        List<ArticleType> all = articleTypeMapper.getAll();
        return all;
    }

    @Override
    @CacheEvict(key = "'tree'")
    public void addData(ArticleType articleType) {
        articleTypeMapper.addData(articleType);
    }

    @Override
    @CacheEvict(key = "'tree'")
    public void updateByID(ArticleType articleType) {
         articleTypeMapper.updateByID(articleType);
    }

    @Override
    @CacheEvict(key = "'tree'")
    public void deleteByID(Long id) {
        articleTypeMapper.deleteByID(id);
    }

    @Override
    public PageInfo<ArticleType> articleTypeLimit(ArticleTypeQuery query) {
        // 1.下面这句代码表示开启分页，会将紧挨着这句代码的下一次数据库执行进行分页，切记一定要放在要分页的SQL语句前面执行
        PageHelper.startPage(query.getCurrentPage(), query.getPageSize());
        List<ArticleType> list = articleTypeMapper.getSearchList(query);
        PageInfo<ArticleType> articleTypePageInfo = new PageInfo<>(list);
        return articleTypePageInfo;
    }

    @Override
    @CacheEvict(key = "'tree'")
    public void batchdelete(List<Long> ids) {
        articleTypeMapper.batchdelete(ids);
    }


    /*无限极树的调用方法
    * 1.使用无限极树的时候我们需要将所有数据先存储到内存中再进行操作：
        因为如果每次进行查询，查询结果不是在内存中的那一份，就很有可能会产生冲突。冲突原因：
        即查数据库后有id=2的对象，若将id=2的对象放在子类集合中的话，起始查到的全部数据中还有id = 2这个对象数据，
        会造成无限极树中父类和子类都有id=2的对象的情况。
      备注：装入list的集合可以是ArticleType对象也可以是ArticleTypeTreeVO（返回值）对象。如果是ArticleType对象，
      还需要新建一个ArticleTypeTreeVO对象把相关字段放入
    * 2.使用方法就是让每个子类自动寻找到它自己的父亲。即要确定没有父亲的类，然后剩下的对象根据本身的parentId找到自己
    * 的父亲，放入父亲集合中
    * 最简单的方法就是根据key value来取值，我们需要将存储所有数据的list集合转化为HashMap集合
    *
    * */
    @Override
    @Cacheable(key = "'tree'")
    public List<ArticleTypeTreeVO> tree() {
        /*1.准备一个集合来接收所有的数据库内的返回值对象。一旦这样，需要重新写一个SQL语句来进行返回。
        SQL语句依旧是select * from table,即让数据库返回所有能查到的列，后端java只接收有用的列*/
        List<ArticleTypeTreeVO> types = articleTypeMapper.getAllData();

        //2.为了快速查找到父亲对象，需要将存储所有数据的list集合转化为HashMap集合
        Map<Long, ArticleTypeTreeVO> map = types
                .stream()
                .collect(Collectors
                        .toMap(ArticleTypeTreeVO::getId, ArticleTypeTreeVO->ArticleTypeTreeVO));

        /*开始遍历Map集合。遍历完成后再放入一个集合，最终返回集合
        1.寻找到没有parentID的对象，将其先放入list中
         */
        List<ArticleTypeTreeVO> treeVOS = new ArrayList<ArticleTypeTreeVO>();
        for (ArticleTypeTreeVO type : types) {
            if (type.getParentId() == null){
                treeVOS.add(type);
            }else {
                ArticleTypeTreeVO parent = map.get(type.getParentId());
                parent.getChildren().add(type);
            }
        }
        return treeVOS;
    }
}
